package xj.model.uml;

import static xj.model.uml.UMLModelConstants.ATTR_DEFAULT_VALUE;
import static xj.model.uml.UMLModelConstants.ATTR_DIRECTION;
import static xj.model.uml.UMLModelConstants.ATTR_TYPE;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

public class Parameter extends NamedElement {

  public enum Direction {
    In, InOut, Out
  };

  public Parameter() {
    this(null, null);
  }

  public Parameter(String name, String type) {
    super(name);
    setType(type);
    destructable = false;
    preserved = true;
  }

  @Override
  public Object clone() throws CloneNotSupportedException {
    Parameter p = (Parameter) super.clone();
    p.setType(type);
    p.setDirection(direction);
    p.setDefaultValue(defaultValue);
    return p;
  }

  public String getType() {
    return type;
  }

  public void setType(String type) {
    this.type = type;
    setAttribute(ATTR_TYPE, type);
  }

  public Direction getDirection() {
    return direction;
  }

  public void setDirection(Direction direction) {
    this.direction = direction;
    setAttribute(ATTR_DIRECTION, direction);
  }

  public String getDefaultValue() {
    return defaultValue;
  }

  public void setDefaultValue(String defaultValue) {
    this.defaultValue = defaultValue;
    setAttribute(ATTR_DEFAULT_VALUE, defaultValue);
  }

  @Override
  public String toString() {
    return (type + " " + name);
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o instanceof Parameter) {
      Parameter e = (Parameter) o;
      if (name == null && e.name != null || 
	  name != null && !name.equals(e.name)) {
	return false;
      }
      if (type == null && e.type != null || 
	  type != null && !type.equals(e.type)) {
	return false;
      }
      if (direction == null && e.direction != null || 
	  direction != null && !direction.equals(e.direction)) {
	return false;
      }
      if (defaultValue == null && e.defaultValue != null || 
	  defaultValue != null && !defaultValue.equals(e.defaultValue)) {
	return false;
      }
      return true;
    }
    return false;
  }

  @Override
  public int hashCode() {
    int c = 0;
    if (name != null) {
      c += (name.hashCode() & 0xFFFF0000);
    }
    if (type != null) {
      c += (type.hashCode() & 0xFFFF);
    }
    return c;
  }

  /*
   * return the papameters represented by the prototype string:
   * 
   * (type param, ...)
   */
  public static List<Parameter> makeParameters(List<Parameter> curparams,
      String proto) {
    if (proto != null) {
      List<Parameter> plist = new ArrayList<Parameter>();
      Parameter param;
      String type;
      String name;
      String token;
      StringTokenizer st = new StringTokenizer(proto.trim(), "(),");
      while (st.hasMoreTokens()) {
	token = st.nextToken();
	/*
         * should be in the form of type name
         */
	type = name = null;
	StringTokenizer st1 = new StringTokenizer(token);
	if (st1.hasMoreTokens()) {
	  type = st1.nextToken();
	}
	if (st1.hasMoreTokens()) {
	  name = st1.nextToken();
	}
	if (name != null && name.length() > 0) {
	  param = null;
	  if (curparams != null) {
	    Iterator<Parameter> iter = curparams.iterator();
	    while (iter.hasNext()) {
	      Parameter p = iter.next();
	      if (name.equals(p.getName())) {
		param = p;
		break;
	      }
	    }
	  }
	  if (param != null) {
	    param.setType(type);
	  } else {
	    param = new Parameter(name, type);
	  }
	  plist.add(param);
	}
      }
      return plist;
    }
    return null;
  }

  protected String type;

  protected Direction direction = Direction.In;

  protected String defaultValue = null;

}
